/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package classe.controlador;

import classe.controlador.exceptions.IllegalOrphanException;
import classe.controlador.exceptions.NonexistentEntityException;
import classe.controlador.util.Constantes;
import java.io.Serializable;
import javax.persistence.Query;
import javax.persistence.EntityNotFoundException;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import classe.entidade.Codificacao;
import classe.entidade.Estoque;
import classe.entidade.Material;
import java.util.ArrayList;
import java.util.List;
import classe.entidade.RequisicaoItem;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;

/**
 * Classe controladora da entidade material
 * @author Kellison
 */
public class MaterialJpaController implements Serializable {

    public MaterialJpaController(EntityManagerFactory emf) {
        this.emf = emf;
    }
        
    public MaterialJpaController() {
        this.emf = Persistence.createEntityManagerFactory(Constantes.UNIDADE_PERSISTENCIA);
    }
    
    private EntityManagerFactory emf = null;

    public EntityManager getEntityManager() {
        return emf.createEntityManager();
    }

    public void create(Material material) {
        if (material.getEstoqueList() == null) {
            material.setEstoqueList(new ArrayList<Estoque>());
        }
        if (material.getRequisicaoItemList() == null) {
            material.setRequisicaoItemList(new ArrayList<RequisicaoItem>());
        }
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Codificacao idTblCodificacao = material.getIdTblCodificacao();
            if (idTblCodificacao != null) {
                idTblCodificacao = em.getReference(idTblCodificacao.getClass(), idTblCodificacao.getId());
                material.setIdTblCodificacao(idTblCodificacao);
            }
            List<Estoque> attachedEstoqueList = new ArrayList<Estoque>();
            for (Estoque estoqueListEstoqueToAttach : material.getEstoqueList()) {
                estoqueListEstoqueToAttach = em.getReference(estoqueListEstoqueToAttach.getClass(), estoqueListEstoqueToAttach.getId());
                attachedEstoqueList.add(estoqueListEstoqueToAttach);
            }
            material.setEstoqueList(attachedEstoqueList);
            List<RequisicaoItem> attachedRequisicaoItemList = new ArrayList<RequisicaoItem>();
            for (RequisicaoItem requisicaoItemListRequisicaoItemToAttach : material.getRequisicaoItemList()) {
                requisicaoItemListRequisicaoItemToAttach = em.getReference(requisicaoItemListRequisicaoItemToAttach.getClass(), requisicaoItemListRequisicaoItemToAttach.getId());
                attachedRequisicaoItemList.add(requisicaoItemListRequisicaoItemToAttach);
            }
            material.setRequisicaoItemList(attachedRequisicaoItemList);
            em.persist(material);
            if (idTblCodificacao != null) {
                idTblCodificacao.getMaterialList().add(material);
                idTblCodificacao = em.merge(idTblCodificacao);
            }
            for (Estoque estoqueListEstoque : material.getEstoqueList()) {
                Material oldIdTblMaterialOfEstoqueListEstoque = estoqueListEstoque.getIdTblMaterial();
                estoqueListEstoque.setIdTblMaterial(material);
                estoqueListEstoque = em.merge(estoqueListEstoque);
                if (oldIdTblMaterialOfEstoqueListEstoque != null) {
                    oldIdTblMaterialOfEstoqueListEstoque.getEstoqueList().remove(estoqueListEstoque);
                    oldIdTblMaterialOfEstoqueListEstoque = em.merge(oldIdTblMaterialOfEstoqueListEstoque);
                }
            }
            for (RequisicaoItem requisicaoItemListRequisicaoItem : material.getRequisicaoItemList()) {
                Material oldIdTblMaterialOfRequisicaoItemListRequisicaoItem = requisicaoItemListRequisicaoItem.getIdTblMaterial();
                requisicaoItemListRequisicaoItem.setIdTblMaterial(material);
                requisicaoItemListRequisicaoItem = em.merge(requisicaoItemListRequisicaoItem);
                if (oldIdTblMaterialOfRequisicaoItemListRequisicaoItem != null) {
                    oldIdTblMaterialOfRequisicaoItemListRequisicaoItem.getRequisicaoItemList().remove(requisicaoItemListRequisicaoItem);
                    oldIdTblMaterialOfRequisicaoItemListRequisicaoItem = em.merge(oldIdTblMaterialOfRequisicaoItemListRequisicaoItem);
                }
            }
            em.getTransaction().commit();
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public void edit(Material material) throws IllegalOrphanException, NonexistentEntityException, Exception {
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Material persistentMaterial = em.find(Material.class, material.getId());
            Codificacao idTblCodificacaoOld = persistentMaterial.getIdTblCodificacao();
            Codificacao idTblCodificacaoNew = material.getIdTblCodificacao();
            List<Estoque> estoqueListOld = persistentMaterial.getEstoqueList();
            List<Estoque> estoqueListNew = material.getEstoqueList();
            List<RequisicaoItem> requisicaoItemListOld = persistentMaterial.getRequisicaoItemList();
            List<RequisicaoItem> requisicaoItemListNew = material.getRequisicaoItemList();
            List<String> illegalOrphanMessages = null;
            for (Estoque estoqueListOldEstoque : estoqueListOld) {
                if (!estoqueListNew.contains(estoqueListOldEstoque)) {
                    if (illegalOrphanMessages == null) {
                        illegalOrphanMessages = new ArrayList<String>();
                    }
                    illegalOrphanMessages.add("Você deve reter Estoque " + estoqueListOldEstoque + " uma vez que o campo idTblMaterial não é anulável.");
                }
            }
            for (RequisicaoItem requisicaoItemListOldRequisicaoItem : requisicaoItemListOld) {
                if (!requisicaoItemListNew.contains(requisicaoItemListOldRequisicaoItem)) {
                    if (illegalOrphanMessages == null) {
                        illegalOrphanMessages = new ArrayList<String>();
                    }
                    illegalOrphanMessages.add("Você deve reter RequisicaoItem " + requisicaoItemListOldRequisicaoItem + " já que seu campo idTblMaterial nao é anulável.");
                }
            }
            if (illegalOrphanMessages != null) {
                throw new IllegalOrphanException(illegalOrphanMessages);
            }
            if (idTblCodificacaoNew != null) {
                idTblCodificacaoNew = em.getReference(idTblCodificacaoNew.getClass(), idTblCodificacaoNew.getId());
                material.setIdTblCodificacao(idTblCodificacaoNew);
            }
            List<Estoque> attachedEstoqueListNew = new ArrayList<Estoque>();
            for (Estoque estoqueListNewEstoqueToAttach : estoqueListNew) {
                estoqueListNewEstoqueToAttach = em.getReference(estoqueListNewEstoqueToAttach.getClass(), estoqueListNewEstoqueToAttach.getId());
                attachedEstoqueListNew.add(estoqueListNewEstoqueToAttach);
            }
            estoqueListNew = attachedEstoqueListNew;
            material.setEstoqueList(estoqueListNew);
            List<RequisicaoItem> attachedRequisicaoItemListNew = new ArrayList<RequisicaoItem>();
            for (RequisicaoItem requisicaoItemListNewRequisicaoItemToAttach : requisicaoItemListNew) {
                requisicaoItemListNewRequisicaoItemToAttach = em.getReference(requisicaoItemListNewRequisicaoItemToAttach.getClass(), requisicaoItemListNewRequisicaoItemToAttach.getId());
                attachedRequisicaoItemListNew.add(requisicaoItemListNewRequisicaoItemToAttach);
            }
            requisicaoItemListNew = attachedRequisicaoItemListNew;
            material.setRequisicaoItemList(requisicaoItemListNew);
            material = em.merge(material);
            if (idTblCodificacaoOld != null && !idTblCodificacaoOld.equals(idTblCodificacaoNew)) {
                idTblCodificacaoOld.getMaterialList().remove(material);
                idTblCodificacaoOld = em.merge(idTblCodificacaoOld);
            }
            if (idTblCodificacaoNew != null && !idTblCodificacaoNew.equals(idTblCodificacaoOld)) {
                idTblCodificacaoNew.getMaterialList().add(material);
                idTblCodificacaoNew = em.merge(idTblCodificacaoNew);
            }
            for (Estoque estoqueListNewEstoque : estoqueListNew) {
                if (!estoqueListOld.contains(estoqueListNewEstoque)) {
                    Material oldIdTblMaterialOfEstoqueListNewEstoque = estoqueListNewEstoque.getIdTblMaterial();
                    estoqueListNewEstoque.setIdTblMaterial(material);
                    estoqueListNewEstoque = em.merge(estoqueListNewEstoque);
                    if (oldIdTblMaterialOfEstoqueListNewEstoque != null && !oldIdTblMaterialOfEstoqueListNewEstoque.equals(material)) {
                        oldIdTblMaterialOfEstoqueListNewEstoque.getEstoqueList().remove(estoqueListNewEstoque);
                        oldIdTblMaterialOfEstoqueListNewEstoque = em.merge(oldIdTblMaterialOfEstoqueListNewEstoque);
                    }
                }
            }
            for (RequisicaoItem requisicaoItemListNewRequisicaoItem : requisicaoItemListNew) {
                if (!requisicaoItemListOld.contains(requisicaoItemListNewRequisicaoItem)) {
                    Material oldIdTblMaterialOfRequisicaoItemListNewRequisicaoItem = requisicaoItemListNewRequisicaoItem.getIdTblMaterial();
                    requisicaoItemListNewRequisicaoItem.setIdTblMaterial(material);
                    requisicaoItemListNewRequisicaoItem = em.merge(requisicaoItemListNewRequisicaoItem);
                    if (oldIdTblMaterialOfRequisicaoItemListNewRequisicaoItem != null && !oldIdTblMaterialOfRequisicaoItemListNewRequisicaoItem.equals(material)) {
                        oldIdTblMaterialOfRequisicaoItemListNewRequisicaoItem.getRequisicaoItemList().remove(requisicaoItemListNewRequisicaoItem);
                        oldIdTblMaterialOfRequisicaoItemListNewRequisicaoItem = em.merge(oldIdTblMaterialOfRequisicaoItemListNewRequisicaoItem);
                    }
                }
            }
            em.getTransaction().commit();
        } catch (Exception ex) {
            String msg = ex.getLocalizedMessage();
            if (msg == null || msg.length() == 0) {
                Integer id = material.getId();
                if (findMaterial(id) == null) {
                    throw new NonexistentEntityException("O material com id " + id + " não existe mais.");
                }
            }
            throw ex;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    /**
     * Metódo modificado de void para boolean
     * @param id
     * @return TRUE ou FALSE
     * @throws IllegalOrphanException
     * @throws NonexistentEntityException 
     */
    public boolean destroy(Integer id) throws IllegalOrphanException, NonexistentEntityException {
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Material material;
            try {
                material = em.getReference(Material.class, id);
                material.getId();
            } catch (EntityNotFoundException enfe) {
                throw new NonexistentEntityException("O material com id " + id + " não mais existe.", enfe);
            }
            List<String> illegalOrphanMessages = null;
            List<Estoque> estoqueListOrphanCheck = material.getEstoqueList();
            for (Estoque estoqueListOrphanCheckEstoque : estoqueListOrphanCheck) {
                if (illegalOrphanMessages == null) {
                    illegalOrphanMessages = new ArrayList<String>();
                }
                illegalOrphanMessages.add("Este Material (" + material + ")não pode ser removido já que o Estoque " + estoqueListOrphanCheckEstoque + " no seu campo estoqueList tem um campo idTblMaterial não anulável.");
            }
            List<RequisicaoItem> requisicaoItemListOrphanCheck = material.getRequisicaoItemList();
            for (RequisicaoItem requisicaoItemListOrphanCheckRequisicaoItem : requisicaoItemListOrphanCheck) {
                if (illegalOrphanMessages == null) {
                    illegalOrphanMessages = new ArrayList<String>();
                }
                illegalOrphanMessages.add("This Material (" + material + ") cannot be destroyed since the RequisicaoItem " + requisicaoItemListOrphanCheckRequisicaoItem + " in its requisicaoItemList field has a non-nullable idTblMaterial field.");
            }
            if (illegalOrphanMessages != null) {
                throw new IllegalOrphanException(illegalOrphanMessages);
            }
            Codificacao idTblCodificacao = material.getIdTblCodificacao();
            if (idTblCodificacao != null) {
                idTblCodificacao.getMaterialList().remove(material);
                idTblCodificacao = em.merge(idTblCodificacao);
            }
            em.remove(material);
            em.getTransaction().commit();
            
            return true;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public List<Material> findMaterialEntities() {
        return findMaterialEntities(true, -1, -1);
    }

    public List<Material> findMaterialEntities(int maxResults, int firstResult) {
        return findMaterialEntities(false, maxResults, firstResult);
    }

    private List<Material> findMaterialEntities(boolean all, int maxResults, int firstResult) {
        EntityManager em = getEntityManager();
        try {
            CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
            cq.select(cq.from(Material.class));
            Query q = em.createQuery(cq);
            if (!all) {
                q.setMaxResults(maxResults);
                q.setFirstResult(firstResult);
            }
            return q.getResultList();
        } finally {
            em.close();
        }
    }

    public Material findMaterial(Integer id) {
        EntityManager em = getEntityManager();
        try {
            return em.find(Material.class, id);
        } finally {
            em.close();
        }
    }
    
    /**
     * Campo de consulta por valores textuais
     * @param campo Campo usado para pesquisa
     * @param valor Valor do campo a ser pesquisado
     * @return List Material
     */
    public List<Material> findMaterial(String campo, String valor) {
        EntityManager em = getEntityManager();
                
        try {
            CriteriaBuilder builder = em.getCriteriaBuilder();
            CriteriaQuery query = builder.createQuery(Material.class);
            Root from = query.from(Material.class);
            
            // Realiza a consulta, filtrando pelo o campo pelo valor passado por parâmetro
            TypedQuery typedQuery = em.createQuery(query.select(from).where(builder.like(from.get(campo),"%" + valor  + "%")));
            
            return typedQuery.getResultList();
        } finally {
            em.close();
        }
        
        
    }

    public int getMaterialCount() {
        EntityManager em = getEntityManager();
        try {
            CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
            Root<Material> rt = cq.from(Material.class);
            cq.select(em.getCriteriaBuilder().count(rt));
            Query q = em.createQuery(cq);
            return ((Long) q.getSingleResult()).intValue();
        } finally {
            em.close();
        }
    }
    
}
